#include "gt_display.h"

#include <cstdlib>
#include <ncurses.h>

#include "gt_entry.h"
#include "gt_theme.h"
#include "gt_util.h"
#include "isearch.h"

// ok
display_t *creare_display() {
  display_t *display;
  display = (display_t *)calloc(1, sizeof(display_t));

  display->cursor = 1;
  display->index = 0;
  display->ncurses_initialized = 0;

  return display;
}

// ok
void start_ncurses(display_t *display, configuration_t *config) {
  initscr();
  cbreak();
  noecho();
  keypad(stdscr, true);
  nodelay(stdscr, true);
  start_color();
  use_default_colors();
  init_pair(1, -1, -1);
  curs_set(0);

  theme_t *thme;
  thme = read_theme(config);
  apply_theme(thme);
  destroy_theme(thme);
}

// ok
void display_results(display_t *display, search_t *search,
                     int terminal_line_nb) {
  int i = 0;
  entry_t *ptr = search->result->start;

  for (i = 0; i < display->index; i++)
    ptr = ptr->next;

  for (i = 0; i < terminal_line_nb; i++) {
    if (ptr && display->index + i < search->result->nbentry) {
      display_entry(ptr, search, i, display->cursor == i);
      if (ptr->next)
        ptr = ptr->next;
    }
  }
}

// ok
static int search_next_upwards(display_t *display, search_t *search,
                               int ignore_current) {
  int next_selectable = display->index + display->cursor;

  if (ignore_current)
    next_selectable -= 1;

  for (; next_selectable > 0; next_selectable--) {
    if (is_selectable(search, next_selectable))
      return next_selectable - display->index;
  }

  return display->cursor;
}

// ok
static int search_next_downwards(display_t *display, search_t *search,
                                 int ignore_current) {
  int next_selectable = display->index + display->cursor;
  if (ignore_current)
    next_selectable += 1;

  for (; next_selectable < search->result->nbentry; next_selectable++) {
    if (is_selectable(search, next_selectable)) {
      return next_selectable - display->index;
    }
  }

  return display->cursor;
}

// ok
void stop_ncurses(display_t *display) { endwin(); }

// ok
void move_cursor_up(display_t *display, search_t *search,
                    int terminal_line_nb) {
  display->cursor = search_next_downwards(display, search, 1);
  if (display->cursor <= 0) {
    move_page_up(display, search, terminal_line_nb);
    clear();
    refresh();
  }
}
// ok
void move_cursor_down(display_t *display, search_t *search,
                      int terminal_line_nb) {
  display->cursor = search_next_downwards(display, search, 1);

  if (display->cursor > (terminal_line_nb - 1)) {
    move_page_down(display, search, terminal_line_nb);
    clear();
    refresh();
  }
}

// ok
void move_page_up(display_t *display, search_t *search, int terminal_line_nb) {
  if (display->index == 0)
    display->cursor = 0;
  else
    display->cursor = terminal_line_nb;

  display->index -= terminal_line_nb;
  display->index = (display->index < 0 ? 0 : display->index);

  if (display->cursor == 0)
    display->cursor = search_next_downwards(display, search, 0);
  else
    display->cursor = search_next_upwards(display, search, 1);
}

// ok
void move_page_down(display_t *display, search_t *search,
                    int terminal_line_nb) {
  int max_index;

  if (search->result->nbentry % terminal_line_nb == 0)
    max_index = (search->result->nbentry - terminal_line_nb);
  else
    max_index = (search->result->nbentry -
                 (search->result->nbentry % terminal_line_nb));

  if (display->index == max_index)
    display->cursor = (search->result->nbentry - 1) % terminal_line_nb;
  else
    display->cursor = 0;

  display->index += terminal_line_nb;
  display->index = (display->index > max_index ? max_index : display->index);

  if (display->cursor == 0)
    display->cursor = search_next_downwards(display, search, 0);
  else
    display->cursor = search_next_upwards(display, search, 0);
}

// ok
void move_page_up_and_refresh(display_t *display, search_t *search) {
  int terminal_line_nb = LINES;
  clear();
  refresh();
  move_page_up(display, search, terminal_line_nb);
  display_results(display, search, terminal_line_nb);
}

// ok
void move_page_down_and_refresh(display_t *display, search_t *search) {
  int terminal_line_nb = LINES;
  clear();
  refresh();
  move_page_down(display, search, terminal_line_nb);
  display_results(display, search, terminal_line_nb);
}
// ok
void move_cursor_up_and_refresh(display_t *display, search_t *search) {
  int terminal_line_nb = LINES;
  move_cursor_up(display, search, terminal_line_nb);
  display_results(display, search, terminal_line_nb);
}
// ok
void move_cursor_down_and_refresh(display_t *display, search_t *search) {
  int terminal_line_nb = LINES;
  move_cursor_down(display, search, terminal_line_nb);
  display_results(display, search, terminal_line_nb);
}
// ok
void resize_display(display_t *display, search_t *search,
                    int terminal_line_nb) {
  clear();
  display_results(display, search, terminal_line_nb);
  refresh();
}
// ok
void free_display(display_t *display) { free(display); }